package com.googlecode.groovy_toy_orm

import com.googlecode.groovy_toy_orm.internal.Util
import groovy.transform.ToString

/**
 * @author: DavydovMD
 * Date: 18.04.13
 * Time: 14:23
 */
@ToString
class Condition {
    /**
     * Mapper field name.
     */
    String field
    ConditionOp op
    /**
     *  Supported types: all scalar, GString , Closure, FieldReference. Closures and GStrings are evaluated during building sql
     */
    def value

    static Condition of(String field, ConditionOp op, def value ){
        new Condition(field: field, op: op, value: value)
    }


    GString buildSql(SingleDbTableMapper mapper) {
        def curValue = value

        if (curValue instanceof Closure) {
            curValue = (curValue as Closure).call()
        } else if (curValue instanceof GString) {
            curValue = (curValue as GString).toString()
        }

        //FieldRef is handled in ConditionOp

        if (mapper.isMultiColumn(field)) {
            if (op == ConditionOp.IN){
                throw new UnsupportedOperationException ("Condition ${this} buildSql failed: IN operator is not compatible with multi-column fields!")
            }
            Map transValues = mapper.getField(field).transformBack(mapper.getField(field), SqlMappingUtil.toCompatible(curValue))
            def fqNames = mapper.getFqSourceNames(field)

            if (transValues.size() == 0) {
                return GString.EMPTY
            }

            GString clause = Util.asGString("(1=1 ")
            transValues.each { Map.Entry<String, String> transValue ->
                clause = clause.plus(Util.asGString(" and " + fqNames.get(transValue.getKey()))).plus(op.buildSql(transValue.getValue()))

            }
            clause = clause.plus(Util.asGString(" ) "))
            return clause;
        } else {
            def transValue = mapper.transformBackFieldValue(field, SqlMappingUtil.toCompatible(curValue))
            return Util.asGString(" ").plus(Util.asGString(mapper.getFqSourceName(field)).toString()).plus(op.buildSql(transValue))
        }


    }

    boolean apply(def left) {
        op.apply(left, value)
    }
}
